import { PtData } from "./PtData";
import { PtPreload } from "./PtPreload";
import { getRegisterComponent, registerComponent } from "./PtRegister";
import { PtStyle } from "./PtStyle";
import type { PtPageJson, DataType, Options, Page, PtComponentConst, ComponentRegister, DataNamespace } from "../types";

/**
 * 整体类
 */
class PtClass {

}

/**
 * 页面类
 */
export class PtPage extends PtClass {
    private project: PtPageJson;
    public data: PtData;
    public style: PtStyle;

    public constructor(project: PtPageJson, data: DataType) {
        super();

        this.project = project;
        this.style = new PtStyle(this.performance);
        this.data = new PtData(data);
    }

    public get performance() {
        return {
            ...this.project.performance
        };
    }

    public setPerformanceWidth(width: number) {
        this.project.performance.width = width;
    }

    public get pages() {
        return this.project.pages;
    }

    public render() {
        return (<>
            {this.pages.map((page: Page) => {
                return <div style="position:relative">
                    {this.getModeRendered(page)}
                </div>
            })}

            {this.renderFooter()}
        </>);
    }

    public getMatchBlobs(page: Page): any[] {
        const origin = Array.isArray(page.origin) ? page.origin : (page.origin || 'base').split('.');
        
        let value: any[] = [this.data.getRaw()];
        
        for (const o of origin) {
            const cur: any[] = [];

            for (const item of value) {
                if (o == '*') {
                    if (Array.isArray(item)) {
                        cur.push(...item);
                    }
                } else if (o in item) {
                    cur.push(item[o]);
                } else {
                    break;
                }
            }

            if (cur.length == 0) {
                break;
            }

            value = cur;
        }

        return value;
    }

    private getModeRendered(page: Page) {
        const blobs = this.getMatchBlobs(page);
        const mode = page.mode || 'normal';

        if (mode == 'loop') {
            return <>
                {blobs.map(blob => {
                    return (new PtContainer(page, this, this.data, blob)).render();
                })}
            </>;
        }

        return (new PtContainer(page, this, this.data, blobs[0])).render();
    }

    private renderFooter() {
        return (<div class="text-slate-400 text-center text-xs mt-4">
            <div>{this.data.getString('org:name')}</div>
            <div class="mt-2">记录时间：{this.data.getString('booklet:recordDate')}</div>
        </div>)
    }

    /**
     * 注册组件
     */
    public static registerComponent(regs: ComponentRegister) {
        registerComponent(regs.name, regs);
    }

    /**
     * 预加载资源
     */
    public async preloadSources(onChange?: (current: number, total: number) => void): Promise<void> {
        const preload = new PtPreload(this);

        return preload.preloadSources(onChange);
    }
}

export class PtContainer {
    private page: Page;
    private parent: PtPage;
    public data: PtData;
    public style: PtStyle;

    constructor(page: Page, parentInstance: PtPage, data: DataType | PtData, namespace: DataNamespace) {
        this.page = page;
        this.parent = parentInstance;
        this.data = data instanceof PtData ? new PtData(data.getRaw(), namespace) : new PtData(data, namespace);
        this.style = parentInstance.style;
    }

    render() {
        return (<div class={'container'} key={Date.now()} style={{'--page-width': this.parent.performance.width + 'px', '--page-height': this.parent.style.balanceSize(this.parent.performance.height) + 'px'}}>
            {this.renderPage()}
            {this.useDeveloperMode(this.page.title)}
        </div>)
    }

    private renderPage() {
        return (<div>
            {this.page.components.map((component: PtComponentConst) => {
                return this.getComponent(component, {
                    name: '',
                    type: 'block',
                    options: {
                        x: 0,
                        y: 0,
                        width: '100%',
                        height: '100%'
                    },
                } as unknown as PtComponentConst);
            })}
        </div>)
    }

    private useDeveloperMode(title: any) {
        const style: any = {
            position: 'absolute',
            top: '0',
            left: '0',
            background: '#ccc',
            color: '#fff',
            fontSize: '12px',
            padding: '6px',
            opacity: '0.65',
            zIndex: 100
        }

        return (<div style={style}>{title}</div>);
    }

    /**
     * 获取页面（子页面）内容结构
     */
    public getComponent(component: PtComponentConst, parent?: PtComponentConst): JSX.Element {
        const rc = getRegisterComponent(component.type);

        if (rc == null) {
            console.warn('没有注册组件：' + component.type);
            return (<div></div>);
        }

        const node = rc.render(this, component, parent);

        return (<node style={this.getComponentStyle(component.options, parent?.options)} />);
    }

    /**
     * 获取页面（子页面）定位样式
     */
    private getComponentStyle = (options: Options, parentOptions?: Options) => {
        return {
            position: 'absolute',
            left: options.positionAlign ? this.parent.style.getAlignStyle(options, (parentOptions ? parentOptions.x : 0) || 0) : this.parent.style.calcSize(options.x),
            top: options.positionVertical ? this.parent.style.getVerticalStyle(options, (parentOptions ? parentOptions.y : 0) || 0) : this.parent.style.calcSize(options.y),
            width: this.parent.style.calcSize(options.width),
            height: this.parent.style.calcSize(options.height),
        }
    }
}